/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.amse.grigory.dchess.view;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import org.amse.grigory.dchess.dchess.DChess;
import org.amse.grigory.dchess.io.*;
import org.amse.grigory.dchess.kernel.*;
import org.amse.grigory.dchess.player.*;
import org.amse.grigory.dchess.rules.Rules;

/**
 *
 * @author grigory
 */
public class DChessFrame extends JFrame implements SwingConstants {

    private static final String ICON_NEW_GAME = "data/img/icons/new game.png";
    private static final String ICON_SAVE = "data/img/icons/save.png";
    private static final String ICON_OPEN = "data/img/icons/open.png";
    private static final String ICON_PAUSE = "data/img/icons/pause.png";
    private static final String ICON_PLAY = "data/img/icons/play.png";
    private static final String ICON_UNDO = "data/img/icons/undo.png";
    private static final String ICON_REDO = "data/img/icons/redo.png";
    private static final int ICON_SIZE = 45;
    private IModel myModel;
    private DChessComponent myDChessComponent;
    private ConfigLoader myConfig;
    private String myTheme,  myRules;
    private int myTime = 100;
    private GameControler myGameController;
    private JButton myPauseButton = null;
    private JMenuItem myPauseMenu = null;
    private DChessLabel myLabelWhite,  myLabelBlack;
    private ClassLoader myClassLoader = DChess.class.getClassLoader();
    //MouseListner

    public DChessFrame() {
        super("DChess");
        ConfigLoader config = null;
        try {
            config = new ConfigLoader();
        } catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(rootPane, "Error can't read config file\n" + ex, "Error", JOptionPane.ERROR_MESSAGE);
            System.exit(0);
        }
        myConfig = config;
        myRules = config.getRules(0);
        myTheme = config.getTheme(0);
        myModel = new Model(myRules);
        // close        
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                int ans = JOptionPane.showConfirmDialog(rootPane, "Do you want to exit?", "Message",
                        JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                if (ans == JOptionPane.YES_OPTION) {
                    System.exit(0);
                }
            }
        });

        //toolbar
        JToolBar mainTb = createToolBar();
        //menubar
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(createFileMenu());
        menuBar.add(createEditMenu());
        menuBar.add(createHelpMenu());
        setJMenuBar(menuBar);
        //
        getContentPane().add(mainTb, BorderLayout.NORTH);
        fillPanel();
        setMinimumSize(new Dimension(900, 600));
        setSize(900, 600);
        setVisible(true);

    }

    private void fillPanel() {
        JPanel mainPanel = new JPanel();
        BoxLayout box = new BoxLayout(mainPanel, BoxLayout.X_AXIS);
        mainPanel.setLayout(box);

        JPanel movePanel = new JPanel();
        movePanel.setMinimumSize(new Dimension(200, 100));
        BoxLayout boxy = new BoxLayout(movePanel, BoxLayout.Y_AXIS);
        movePanel.setLayout(boxy);
        movePanel.setPreferredSize(new Dimension(250, 100));

        Dimension dim = new Dimension();
        // Adding board
        DChessComponent dchessComponent = null;
        dchessComponent = new DChessComponent(myModel, null, null);
        dchessComponent.setBorder(BorderFactory.createEtchedBorder());
        dim.height = ICON_SIZE * 8;
        dim.width = ICON_SIZE * 8;
        dchessComponent.setVisible(false);
        dchessComponent.setSize(dim);
        dchessComponent.setPreferredSize(dim);
        myDChessComponent = dchessComponent;

        // Adding text field
        DChessText text = new DChessText(myModel);
        text.setFocusable(false);
        text.setCursor(Cursor.getDefaultCursor());
        myModel.addListener(text);
        //scrollbar
        JScrollPane scroll = new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setMaximumSize(new Dimension(250, 2000));
        scroll.setPreferredSize(new Dimension(250, 2000));
        scroll.setBorder(BorderFactory.createTitledBorder("Moves"));

        myLabelBlack = new DChessLabel(myModel, Rules.COLOR_BLACK);
        myModel.addListener(myLabelBlack);
        myLabelBlack.setVisible(true);

        myLabelWhite = new DChessLabel(myModel, Rules.COLOR_WHITE);
        myModel.addListener(myLabelWhite);
        myLabelWhite.setVisible(true);

        mainPanel.add(Box.createHorizontalGlue());
        mainPanel.add(dchessComponent);
        mainPanel.add(movePanel);
        mainPanel.add(Box.createHorizontalGlue());
        mainPanel.add(scroll);

        movePanel.add(Box.createVerticalGlue());
        movePanel.add(myLabelBlack);
        movePanel.add(Box.createVerticalGlue());
        movePanel.add(myLabelWhite);
        movePanel.add(Box.createVerticalGlue());
        getContentPane().add(mainPanel, BorderLayout.CENTER);


    }

    private JMenu createFileMenu() {
        JMenu file = new JMenu("File");
        file.setMnemonic('F');
        // Creating File
        JMenuItem newGame = new JMenuItem(new NewAction());
        newGame.setText("New Game");
        newGame.setAccelerator(KeyStroke.getKeyStroke('N', KeyEvent.CTRL_MASK));
        JMenuItem open = new JMenuItem(new OpenAction());
        open.setText("Open");
        open.setAccelerator(KeyStroke.getKeyStroke('O', KeyEvent.CTRL_MASK));
        JMenuItem save = new JMenuItem(new SaveAction());
        save.setText("Save");
        save.setAccelerator(KeyStroke.getKeyStroke('S', KeyEvent.CTRL_MASK));
        JMenuItem exit = new JMenuItem(new ExitAction());
        exit.setAccelerator(KeyStroke.getKeyStroke('Q', KeyEvent.CTRL_MASK));
        // Adding Items
        setFocusable(false);
        file.add(newGame);
        file.add(open);
        file.add(save);
        file.addSeparator();
        file.add(exit);
        return file;
    }

    private JMenu createEditMenu() {
        JMenu edit = new JMenu("Edit");
        edit.setMnemonic('E');
        JMenuItem pause = new JMenuItem(new PauseAction());
        pause.setEnabled(false);
        pause.setAccelerator(KeyStroke.getKeyStroke('P', KeyEvent.CTRL_MASK));
        myPauseMenu = pause;

        DChessMenuItem buttonUndo = new DChessMenuItem(new UndoAction(), DChessButton.BUTTON_UNDO, myModel);
        buttonUndo.setEnabled(false);
        buttonUndo.setAccelerator(KeyStroke.getKeyStroke('Z', KeyEvent.CTRL_MASK));
        myModel.addListener(buttonUndo);

        DChessMenuItem buttonRedo = new DChessMenuItem(new RedoAction(), DChessButton.BUTTON_REDO, myModel);
        buttonRedo.setEnabled(false);
        buttonRedo.setAccelerator(KeyStroke.getKeyStroke('Y', KeyEvent.CTRL_MASK));
        myModel.addListener(buttonRedo);
        edit.add(pause);
        edit.add(buttonUndo);
        edit.add(buttonRedo);
        return edit;
    }

    private JMenu createHelpMenu() {
        JMenu edit = new JMenu("Help");
        edit.setMnemonic('H');
        JMenuItem help = new JMenuItem(new HelpAction());
        help.setAccelerator(KeyStroke.getKeyStroke('H', KeyEvent.CTRL_MASK));
        JMenuItem about = new JMenuItem(new AboutAction());
        edit.add(help);
        edit.add(about);
        return edit;
    }

    private class HelpAction extends AbstractAction {

        public HelpAction() {
            putValue(NAME, "Help");
        }

        public void actionPerformed(ActionEvent e) {
            new HelpDialog(DChessFrame.this);
        }
    }

    private class AboutAction extends AbstractAction {

        public AboutAction() {
            putValue(NAME, "About");
        }

        public void actionPerformed(ActionEvent e) {
            new AboutDialog(DChessFrame.this);
        }
    }

    private class ExitAction extends AbstractAction {

        public ExitAction() {
            putValue(NAME, "Exit");
            putValue(SHORT_DESCRIPTION, "Exit game");
        }

        public void actionPerformed(ActionEvent e) {
            int ans = JOptionPane.showConfirmDialog(rootPane, "Do you want to exit?", "Message",
                    JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
            if (ans == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }
    }

    private class OpenAction extends AbstractAction {

        public OpenAction() {
            putValue(SMALL_ICON, new ImageIcon(myClassLoader.getResource(ICON_OPEN)));
            putValue(SHORT_DESCRIPTION, "Open saved game");
        }

        public void actionPerformed(ActionEvent e) {
            new OpenGameDialog(DChessFrame.this);
        }
    }

    private class SaveAction extends AbstractAction {

        public SaveAction() {
            putValue(SMALL_ICON, new ImageIcon(myClassLoader.getResource(ICON_SAVE)));
            putValue(SHORT_DESCRIPTION, "Save current game");
        }

        public void actionPerformed(ActionEvent e) {
            if (myModel.getHeight() == 0) {
                return;
            }
            JFileChooser fc = new JFileChooser();
            fc.setDialogTitle("Save Game");
            fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
            fc.setFileFilter(Filters.getGameFilter());
            fc.setCurrentDirectory(new File("."));
            int res = fc.showSaveDialog(DChessFrame.this);
            if ((res == JFileChooser.APPROVE_OPTION)) {
                try {
                    File f = fc.getSelectedFile();
                    if (!f.getName().endsWith("xml")) {
                        f = new File(f.getName() + ".xml");
                    }
                    GameSaver.save(myModel, f);
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(rootPane, ex.toString(), "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    private class NewAction extends AbstractAction {

        public NewAction() {
            putValue(SMALL_ICON, new ImageIcon(myClassLoader.getResource(ICON_NEW_GAME)));
            putValue(SHORT_DESCRIPTION, "Start new game");
        }

        public void actionPerformed(ActionEvent e) {
            new NewGameDialog(DChessFrame.this);
        }
    }

    private class UndoAction extends AbstractAction {

        public UndoAction() {
            putValue(SMALL_ICON, new ImageIcon(myClassLoader.getResource(ICON_UNDO)));
            putValue(SHORT_DESCRIPTION, "undo");
        }

        public void actionPerformed(ActionEvent e) {
            myGameController.undo();
        }
    }

    private class RedoAction extends AbstractAction {

        public RedoAction() {
            putValue(SMALL_ICON, new ImageIcon(myClassLoader.getResource(ICON_REDO)));
            putValue(SHORT_DESCRIPTION, "redo");
        }

        public void actionPerformed(ActionEvent e) {
            myGameController.redo();
        }
    }

    private class PauseAction extends AbstractAction {

        public PauseAction() {
            putValue(SMALL_ICON, new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
            putValue(NAME, "Pause");
        }

        public void actionPerformed(ActionEvent e) {
            if (myModel.isPaused()) {
                myModel.continueGame();
                myPauseButton.setText("Pause");
                myPauseButton.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
                myPauseMenu.setText("Pause");
                myPauseMenu.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
                putValue(NAME, "Pause");
                ImageIcon icon = new ImageIcon(myClassLoader.getResource(ICON_PAUSE));
                putValue(SMALL_ICON, icon);
            } else {
                myModel.pause();
                myPauseButton.setText("Continue");
                myPauseButton.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PLAY)));
                myPauseMenu.setText("Continue");
                myPauseMenu.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PLAY)));
                putValue(NAME, "Continue");
                ImageIcon icon = new ImageIcon(myClassLoader.getResource(ICON_PLAY));
                putValue(SMALL_ICON, icon);
            }

        }
    }

    private JToolBar createToolBar() {
        JToolBar tb = new JToolBar();
        tb.setFloatable(false);

        JToolBar tb1 = new JToolBar();
        JButton buttonN = new JButton(new NewAction());
        JButton buttonO = new JButton(new OpenAction());
        JButton buttonS = new JButton(new SaveAction());
        tb1.add(buttonN);
        tb1.add(buttonO);
        tb1.add(buttonS);

        JToolBar tb2 = new JToolBar();
        JButton jButton = new JButton(new PauseAction());
        myPauseButton = jButton;
        jButton.setEnabled(false);
        DChessButton buttonUndo = new DChessButton(new UndoAction(), DChessButton.BUTTON_UNDO, myModel);
        buttonUndo.setEnabled(false);
        myModel.addListener(buttonUndo);

        DChessButton buttonRedo = new DChessButton(new RedoAction(), DChessButton.BUTTON_REDO, myModel);
        buttonRedo.setEnabled(false);
        myModel.addListener(buttonRedo);

        tb2.add(jButton);
        tb2.add(buttonUndo);
        tb2.add(buttonRedo);

        //------
        tb.add(tb1);
        tb.add(tb2);
        return tb;

    }
    /*
    private class RulesAction extends AbstractAction {
    
    public RulesAction() {
    putValue(NAME, "Rules: classical");
    }
    
    public void actionPerformed(ActionEvent e) {
    JFileChooser fc = new JFileChooser();
    fc.addChoosableFileFilter(new RulesFilter();
    fc.setDialogTitle("Choose Rules");
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
    fc.setCurrentDirectory(new File("./rules"));
    int res = fc.showOpenDialog(DChessFrame.this);
    if ((res == JFileChooser.APPROVE_OPTION) && (fc.getSelectedFile().exists())) {
    File f = fc.getSelectedFile();new
    myModel.setRulesFile(f.getPath());
    int i = 0;
    while (i < f.getName().length() - 1) {
    if (f.getName().charAt(i) == '.') {
    break;
    }
    ++i;
    }
    putValue(NAME, "Rules: " + f.getName().substring(0, i));
    }
    }
    }
    
    private class ThemeAction extends AbstractAction {
    
    public ThemeAction() {
    putValue(NAME, "Theme: default");
    }
    
    public void actionPerformed(ActionEvent e) {
    JFileChooser fc = new JFileChooser();
    fc.addChoosableFileFilter(new ThemeFilter());
    fc.setDialogTitle("Choose Rules");
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
    fc.setCurrentDirectory(new File("./themes"));
    int res = fc.showOpenDialog(DChessFrame.this);
    if ((res == JFileChooser.APPROVE_OPTION) && (fc.getSelectedFile().exists())) {
    File f = fc.getSelectedFile();
    int i = 0;
    while (i < f.getName().length() - 1) {
    if (f.getName().charAt(i) == '.') {
    break;
    }
    ++i;
    }
    putValue(NAME, "Theme: " + f.getName().substring(0, i));
    }
    }
    }
    
    private class RulesFilter extends FileFilter {
    
    @Override
    public boolean accept(File f) {
    if (f.isDirectory()) {
    return true;
    }
    return f.getName().endsWith("rl");
    }
    
    @Override
    public String getDescription() {
    return "Files with rules (*.rl)";
    }
    }
    
    private class ThemeFilter extends FileFilter {
    
    @Override
    public boolean accept(File f) {
    if (f.isDirectory()) {
    return true;
    }
    return f.getName().endsWith("thm");
    }
    
    @Override
    public String getDescription() {
    return "Files with theme (*.thm)";
    }
    }*/

    // Simple Methods
    public String getRules() {
        return myRules;
    }

    public String getTheme() {
        return myTheme;
    }

    public ConfigLoader getConfig() {
        return myConfig;
    }

    public GameControler getGameControler() {
        return myGameController;
    }

    public IModel getModel() {
        return myModel;
    }

    public void setRules(String rules) {
        myRules = rules;
    }

    public void setTheme(String theme) {
        myTheme = theme;
    }

    public void setTime(int time) {
        myModel.setTime(time);
    }

    public void openGame(GameControler gamecontroler, String path) {
        try {
            new GameLoader().loadGame(myModel, new File(path));
            ThemeLoader.loadTheme(myDChessComponent.getTheme(), myTheme);
            if (myGameController != null) {
                myGameController.kill();
            }
            myGameController = gamecontroler;
            gamecontroler = null;
            if (myGameController.getBlackPlayer() instanceof LocalPlayer) {
                myDChessComponent.setBlackPlayer((LocalPlayer) myGameController.getBlackPlayer());
                myLabelBlack.setLabelName("Local player");
            } else {
                myDChessComponent.setBlackPlayer(null);
                myLabelBlack.setLabelName("AI player");
            }
            if (myGameController.getWhitePlayer() instanceof LocalPlayer) {
                myDChessComponent.setWhitePlayer((LocalPlayer) myGameController.getWhitePlayer());
                myLabelWhite.setLabelName("Local player");
            } else {
                myDChessComponent.setWhitePlayer(null);
                myLabelWhite.setLabelName("AI player");
            }            
            myPauseButton.setEnabled(true);
            myPauseButton.setText("Pause");
            myPauseButton.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
            myPauseMenu.setEnabled(true);
            myPauseMenu.setText("Pause");
            myPauseMenu.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
            myDChessComponent.setVisible(false);
            int h = ICON_SIZE * myModel.getHeight();
            int w = ICON_SIZE * myModel.getWidth();
            Dimension dim = new Dimension();
            dim.height = h;
            dim.width = w;
            myDChessComponent.setMaximumSize(dim);
            myDChessComponent.setMinimumSize(dim);
            myDChessComponent.setPreferredSize(dim);
            myDChessComponent.setVisible(true);
            myGameController.start();            
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(rootPane, ex.toString(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    public void startGame(GameControler gamecontroler) {
        myModel.setRulesFile(myRules);
        boolean isIO = true;
        try {
            ThemeLoader.loadTheme(myDChessComponent.getTheme(), myTheme);
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(rootPane, "Error while reading theme file:" + myTheme, "Error", JOptionPane.ERROR_MESSAGE);
            isIO = false;
        }
        if (isIO) {
            try {
                myModel.newGame();
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(rootPane, "Error while reading file with rules:" + myRules, "Error", JOptionPane.ERROR_MESSAGE);
                isIO = false;
            }
            if (isIO) {
                if (myGameController != null) {
                    myGameController.kill();
                }
                myGameController = gamecontroler;
                gamecontroler = null;
                if (myGameController.getBlackPlayer() instanceof LocalPlayer) {
                    myDChessComponent.setBlackPlayer((LocalPlayer) myGameController.getBlackPlayer());
                    myLabelBlack.setLabelName("Local player");
                } else {
                    myDChessComponent.setBlackPlayer(null);
                    myLabelBlack.setLabelName("AI player");
                }
                if (myGameController.getWhitePlayer() instanceof LocalPlayer) {
                    myDChessComponent.setWhitePlayer((LocalPlayer) myGameController.getWhitePlayer());
                    myLabelWhite.setLabelName("Local player");
                } else {
                    myDChessComponent.setWhitePlayer(null);
                    myLabelWhite.setLabelName("AI player");
                }
                myModel.start();
                myPauseButton.setEnabled(true);
                myPauseButton.setText("Pause");
                myPauseButton.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
                myPauseMenu.setEnabled(true);
                myPauseMenu.setText("Pause");
                myPauseMenu.setIcon(new ImageIcon(myClassLoader.getResource(ICON_PAUSE)));
                myDChessComponent.setVisible(false);
                int h = ICON_SIZE * myModel.getHeight();
                int w = ICON_SIZE * myModel.getWidth();
                Dimension dim = new Dimension();
                dim.height = h;
                dim.width = w;
                myDChessComponent.setMaximumSize(dim);
                myDChessComponent.setMinimumSize(dim);
                myDChessComponent.setPreferredSize(dim);
                myDChessComponent.setVisible(true);
                myGameController.start();                
            }
        }
    }
}
